#pragma once

#include "DatabaseConnection.h"

struct RawEntityFeed
{
    ResultCol<Type_UINTEGER>        id;
    ResultCol<Type_STRING, 10>      name;
    ResultCol<Type_STRING, 255>     description;
    ResultCol<Type_STRING, 10>      pnacprefix;
    ResultCol<Type_STRING, 10>      attributioin;
    ResultCol<Type_INTEGER>         alertstatus;
    ResultCol<Type_STRING, 300>     emaillist;
};

struct RawEntityAlert
{
    ResultCol<Type_UINTEGER>        id;
    ResultCol<Type_UINTEGER>        feedRuleId;
    ResultCol<Type_STRING, 1000>    message;
    ResultCol<Type_INTEGER>         alertstatus;
    ResultCol<Type_INTEGER>         flag;
};

struct RawEntityRule
{
    ResultCol<Type_UINTEGER>        id;
    ResultCol<Type_STRING, 10>      name;
    ResultCol<Type_STRING, 500>     description;
    ResultCol<Type_STRING, 500>     format;
};

struct RawEntityFeedRule
{
    ResultCol<Type_UINTEGER>        id;
    ResultCol<Type_UINTEGER>        feedID;
    ResultCol<Type_UINTEGER>        ruleID;
    ResultCol<Type_INTEGER>         alertStatus;
};

//This object deals with database operations
class DataBaseAccessObject
{
public:
    void QueryAlertList( std::vector<RawEntityAlert>& alerts, std::vector<RawEntityFeed>& feeds )
    {
        RawEntityAlert alert;
        RawEntityFeed  feed;
        try
        {
            m_selectAlertStatement->Execute();
            
            alert.id.BindStatement( m_selectAlertStatement.get(), 1 );
            alert.feedRuleId.BindStatement( m_selectAlertStatement.get(), 2 );
            alert.message.BindStatement( m_selectAlertStatement.get(), 3 );
            alert.alertstatus.BindStatement( m_selectAlertStatement.get(), 4 );
            alert.flag.BindStatement( m_selectAlertStatement.get(), 5 );
            feed.id.BindStatement( m_selectAlertStatement.get(), 6 );

            while( m_selectAlertStatement->FetchNext() )
            {
                //We get one alert entity
                alerts.push_back( alert );
                feeds.push_back( feed );
            }

            m_selectAlertStatement->FetchEnd();
        }
        catch( DataBaseException& e )
        {
            std::cout << "Failed to get alert list" << std::endl;
            std::cout << "DBError: " << e.what() << std::endl;
        }
    }

    void UpdateAlertFlag( RawEntityAlert* alert )
    {
        try
        {
            //Update the information based on its id
            StatementParam param1( Param_Input, SQL_C_ULONG, SQL_INTEGER ); 
            param1.SetValue<int>( alert->flag.GetValue<int>() );

            m_updateAlertStatement->BindParameter( 
                1, 
                &param1 );

            StatementParam param2( Param_Input, SQL_C_ULONG, SQL_INTEGER );
            param2.SetValue<int>( alert->id.GetValue<int>() );

            m_updateAlertStatement->BindParameter(
                2,
                &param2 );

            m_updateAlertStatement->Execute();

        }
        catch( DataBaseException& e )
        {
            std::cout << e.what() << std::endl;
        }
    }

    void UpdateFeedStatus( RawEntityFeed* feed, RawEntityFeedRule* feedRule )
    {
        try
        {
            StatementParam alertStatusParam( Param_Input, SQL_C_ULONG, SQL_INTEGER );
            alertStatusParam.SetValue<int>( feed->alertstatus.GetValue<int>() );
            m_updateFeedStatusStatement->BindParameter( 1, &alertStatusParam );

            StatementParam idParam( Param_Input, SQL_C_ULONG, SQL_INTEGER );
            idParam.SetValue<int>( feed->id.GetValue<int>() );
            m_updateFeedStatusStatement->BindParameter( 2, &idParam );

            m_updateFeedStatusStatement->Execute();


            StatementParam alertStatusFRParam( Param_Input, SQL_C_ULONG, SQL_INTEGER );
            alertStatusFRParam.SetValue<int>( feedRule->alertStatus.GetValue<int>() );
            m_updateFeedRuleStatusStatement->BindParameter( 1, &alertStatusFRParam );

            StatementParam feedRuleId( Param_Input, SQL_C_ULONG, SQL_INTEGER );
            feedRuleId.SetValue<int>( feedRule->id.GetValue<int>() );

            m_updateFeedRuleStatusStatement->BindParameter( 2, &feedRuleId );
            m_updateFeedRuleStatusStatement->Execute();

        }
        catch( DataBaseException& e )
        {
            std::cout << "Failed in Update feed status " << std::endl;
            std::cout << e.what() << std::endl;
        }
    }

    DataBaseAccessObject( 
        const std::string& serverName, 
        const std::string& userName,
        const std::string& authentication )
        :m_serverName( serverName )
        ,m_userName( userName )
        ,m_authentication( authentication )
    {
        try
        {
            m_dbConnection.Initialize();
            //m_dbConnection.Connect( "NEWSM_COL2_SQLSERVER", "sa", "Tin.netS1" );
            m_dbConnection.Connect( m_serverName.c_str(),
                m_userName.c_str(),
                m_authentication.c_str() );

            m_selectAlertStatement = 
                m_dbConnection.CreateStatement(
                    L"select alert.id, alert.feedRuleID, alert.message, alert.alertStatus, alert.flag, feedRules.feedID \n"
                    L"from alert INNER JOIN \n"
                    L"feedRules ON alert.feedRuleID = feedRules.id \n"
                    L"where ( alert.flag <> 1 )"

                    );
            m_selectAlertStatement->Prepare();

            m_updateAlertStatement = 
                m_dbConnection.CreateStatement(
                    L"update alert "
                    L"set flag = ? "
                    L"where ( id = ? ) "
                    );
            m_updateAlertStatement->Prepare();

            m_updateFeedStatusStatement = 
                m_dbConnection.CreateStatement(
                    L"UPDATE feed \n"
                    L"SET alertStatus = ? "
                    L"WHERE ( id = ? ) " );
            m_updateFeedStatusStatement->Prepare();    
            
            m_updateFeedRuleStatusStatement = 
                m_dbConnection.CreateStatement(
                    L"UPDATE feedRules "
                    L"SET alertStatus = ? "
                    L"WHERE ( id = ? ) " );
            m_updateFeedRuleStatusStatement->Prepare();
            
        }
        catch( DataBaseException& e )
        { 
            std::cout << e.what();
        }
    }

    ~DataBaseAccessObject()
    {
        m_dbConnection.DisConnect();
        m_dbConnection.UnInitialize();
    }
private:
    DataBaseConnection m_dbConnection;
    std::shared_ptr<DataBaseStatement>  m_selectAlertStatement;
    std::shared_ptr<DataBaseStatement>  m_updateAlertStatement;
    std::shared_ptr<DataBaseStatement>  m_selectFeedInfomation;
    std::shared_ptr<DataBaseStatement>  m_updateFeedStatusStatement;
    std::shared_ptr<DataBaseStatement>  m_updateFeedRuleStatusStatement;

    std::string m_serverName;
    std::string m_userName;
    std::string m_authentication;
};